package com.wang.tx;

import com.alibaba.druid.pool.DruidDataSource;
import com.wang.tx.tcc.TccTx;
import com.wang.utils.DatabaseUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.StampedLock;

public class Demo {

    public static class Transfer {
        private String from;
        private String to;
        private int amount;

        public String getFrom() {
            return from;
        }

        public void setFrom(String from) {
            this.from = from;
        }

        public String getTo() {
            return to;
        }

        public void setTo(String to) {
            this.to = to;
        }

        public int getAmount() {
            return amount;
        }

        public void setAmount(int amount) {
            this.amount = amount;
        }
    }

    public static class User {
        private long id;
        private String name;
        private long money;
        private long frozen;

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public long getMoney() {
            return money;
        }

        public void setMoney(long money) {
            this.money = money;
        }

        public long getFrozen() {
            return frozen;
        }

        public void setFrozen(long frozen) {
            this.frozen = frozen;
        }
    }

    private static Connection conn;

    public static void main(String[] args) throws Exception {
        DataSource dataSource = dataSource();
        conn = DatabaseUtils.INSTANCE.openConnection("localhost", "3306", "wdj", "root", "root");
        conn.setAutoCommit(false);
        Transfer transfer = new Transfer();
        transfer.from = "2";
        transfer.to = "1";
        transfer.amount = 5;
//        manager.execute(transfer);
//        manager.execute(transfer);
    }

    public static DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/wdj?useSSL=false&serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        return dataSource;
    }


    public static class TransferTx extends TccTx {
        private Connection connection;
        private String user;
        private boolean isSub;
        private int amount;

        public TransferTx(Connection connection, String user, boolean isSub, int amount) {
            this.connection = connection;
            this.user = user;
            this.isSub = isSub;
            this.amount = amount;
        }

        @Override
        protected boolean execute() throws Throwable {
            connection.setAutoCommit(false);
            //测试有一个try成功，一个try失败后，奔溃的情况
//            if(f) {
//                f = false;
//            } else {
//                return false;
//            }
            User u = DatabaseUtils.INSTANCE.select(Demo.conn, "select * from user where id = " + user, User.class).get(0);
            long originAmount = u.money;
            u.money = isSub ? originAmount - amount : originAmount;
            u.frozen += amount;
            DatabaseUtils.INSTANCE.update(Demo.conn, "update user set money = " + u.money +
                    ", frozen = " + u.frozen + " where id = " + user);
            conn.commit();
            return true;
        }

        @Override
        public void commit() {
//            connection.setAutoCommit(false);
            //测试try之后奔溃的情况
            //if(true) throw new Exception();
            User u = DatabaseUtils.INSTANCE.select(Demo.conn, "select * from user where id = " + user, User.class).get(0);
            u.frozen -= amount;
            u.money = isSub ? u.money : u.money + amount;
            DatabaseUtils.INSTANCE.update(Demo.conn, "update user set money = " + u.money +
                    ", frozen = " + u.frozen + " where id = " + user);
//            Demo.conn.commit();
        }

        @Override
        public void rollback() {
//            connection.setAutoCommit(false);
            //测试有一个try成功，一个try失败后，奔溃的情况
//            if(true) throw new Error();
            User u = DatabaseUtils.INSTANCE.select(Demo.conn, "select * from user where id = " + user, User.class).get(0);
            u.money = isSub ? u.money + amount : u.money;
            u.frozen -= amount;
            DatabaseUtils.INSTANCE.update(Demo.conn, "update user set money = " + u.money +
                    ", frozen = " + u.frozen + " where id = " + user);
//            Demo.conn.commit();
        }
    }

     public static class ALock extends AbstractQueuedSynchronizer {
         @Override
         protected boolean tryAcquire(int arg) {
             return super.tryAcquire(arg);
         }
     }
}
